package com.brand.data.service.yqdz;

import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.PostConstruct;

import org.apache.commons.io.FileUtils;
import org.jsoup.Connection.Method;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.brand.data.model.MonitorException;
import com.brand.data.model.TipMess;
import com.brand.data.model.event.TipEvent;
import com.brand.data.service.OrderTaskService;
import com.brand.data.service.SpiderService;
import com.brand.data.util.DateUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * @author scl
 * @date 2018年4月26日 上午11:04:11
 * @version 1.0
 * @description  一汽大众
 */
@Service
@Slf4j
public class YqdzTaskService implements OrderTaskService {
	static boolean flag = false;
	private String url;
	private JSONArray orders;
	private File orderFile;
	private LinkedHashMap<String, JSONObject> orderContainer = new LinkedHashMap<>();
	@Autowired
	private ThreadPoolTaskExecutor pool;
	@Autowired
	@Qualifier("yqdzSpider")
	private SpiderService spiderService;
	@Autowired
	private ApplicationContext applicationContext;
	@PostConstruct
	private void init(){
		url = PULL_URL + spiderService.getBrandCode();
		orderFile = new File("orders/"+spiderService.getBrandCode()+DateUtils.date2ShortDay(new Date())+".txt");
		readOrders();
	}
	@Override
	@Scheduled(cron="0/10 * * * * ? ")
	public void pull() {
		try {
			//当没有订单的时候取任务中心拉取订单
//			if (orderContainer == null || orderContainer.isEmpty()) {
				if (flag) {
					log.info("开始拉取订单");
					String body = Jsoup.connect(url).ignoreContentType(true).timeout(30000)
							.method(Method.GET).execute().body();
					orders = JSON.parseArray(body);
					if (!orders.isEmpty()) {
						saveOrders(orders);
						writeOrders();
					}
					log.info("订单获取结果:{}",orders);
				}
//			}
		} catch (Exception e) {
			log.error("获取订单异常",e);
		}
	}
	/**
	 * @param orders2
	 */
	private void saveOrders(JSONArray orders) {
		for (Object obj : orders) {
			JSONObject order = (JSONObject) obj;
			orderContainer.put(order.getString("id"), order);
		}
	}
	private void writeOrders(){
		try {
			File orderFile = new File("orders/"+spiderService.getBrandCode()+DateUtils.date2ShortDay(new Date())+".txt");
			if (!orderFile.exists()) {
				try {
					FileUtils.forceMkdirParent(orderFile);
					orderFile.createNewFile();
				} catch (IOException e) {}
			}
			synchronized (YqdzTaskService.class) {
				String orderStr = JSON.toJSONString(orderContainer);
				FileUtils.write(orderFile, orderStr, Charset.defaultCharset());
			}
			delHistoryOrders();
		} catch (Exception e) {
		}
	}
	private void readOrders(){
		try {
			String orderStr = FileUtils.readFileToString(orderFile, Charset.defaultCharset());
			orderContainer = JSON.parseObject(orderStr, orderContainer.getClass());
		} catch (Exception e) {
		}
	}
	private static final long maxDiff=5*24*60*60*1000;
	private void delHistoryOrders(){
		try {
			long now = System.currentTimeMillis();
			File orderFile = new File("orders/");
			if (orderFile.exists()) {
				File[] listFiles = orderFile.listFiles();
				for (File file : listFiles) {
					long lastModified = file.lastModified();
					long diff = now - lastModified;
					if (diff >= maxDiff) {
						file.delete();
					}
				}
			}
		} catch (Exception e) {
		}
	}
	@Override
	@Scheduled(cron="0/5 * * * * ? ")
	public void push() {
		try {
			if (flag && orderContainer != null && !orderContainer.isEmpty()) {
				log.info("开始查询车辆信息");
//				Set<String> orderIds = new HashSet<>(orderContainer.keySet());
				
				ListIterator<Map.Entry<String,JSONObject>> i=new ArrayList<>(orderContainer.entrySet()).listIterator(orderContainer.size());
				
				while(i.hasPrevious()){
					Entry<String, JSONObject> orderMap=i.previous();
					JSONObject order = orderMap.getValue();
					pool.submit(new Thread() {
						@Override
						public void run() {
							try {
								push(order);
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					});
				}
			}
		} catch (Exception e) {
			log.error("推送订单查询结果异常",e);
		}
	}
	private void push(JSONObject order) throws IOException {
		String enginnum = order.getString("enginnum");
		String vin = order.getString("vin");
		String code = ResultStatus.SUCCESS;
		Object data;
		try {
			data = spiderService.query(vin, enginnum);
			orderContainer.remove(order.getString("id"));
			if (((Collection)data).isEmpty()) {
				log.info("vin{}查无记录",vin);
				code = ResultStatus.NORECORD;
			}
		} catch (Exception e) {
			log.error("vin"+vin+"查询失败",e);
			data = new ArrayList<>();
			code = ResultStatus.ERROR;
			String title = "系统异常"+e.getMessage();
			if (e instanceof MonitorException) {
				title = ((MonitorException)e).getTitle();
			}
			if (isServerStop(e)) {
				title = "系统维护";
				code = ResultStatus.MAINTAIN;
			}
			applicationContext.publishEvent(new TipEvent(new TipMess(spiderService.getBrandName(), title,vin)));
		}
		if (isPush(code)) {
			JSONObject obj = new JSONObject();
			obj.put("code", code);
			obj.put("info", order);
			obj.put("data", data);
			push(obj,vin, 0);
		}
	}
	private boolean isPush(String code){
		return !ResultStatus.ERROR.equals(code)&&!ResultStatus.MAINTAIN.equals(code);
	}
	/**
	 * 推送查询结果，推送10次
	 * @param obj
	 * @return
	 * @throws IOException
	 */
	private void push(JSONObject obj,String vin,int times) throws IOException {
		if (times < 10 ) {
			try {
				String body = Jsoup.connect(PUSH_URL).ignoreContentType(true)
						.header("Content-Type", "application/json").timeout(30000)
						.requestBody(obj.toJSONString())
						.method(Method.POST).execute()
						.body();
				writeOrders();
				log.info("vin{}-->推送查询数据{}==>结果反馈:{}",vin,obj.toJSONString(),body);
			} catch (Exception e) {
				push(obj,vin,++times);
				e.printStackTrace();
			}
		}
	}
	
	private static final String TEST_VIN="LFV2A2156G3043206";
	/**
	 * 服务监控
	 */
	@Scheduled(cron="0 0/1 5-23 * * ? ")
	public void monitorServer(){
		log.info("测试服务器{}连通性",spiderService.getBrandName());
		try {
			spiderService.query(TEST_VIN, null);
			if (!flag) {
				flag=true;
				updateBrandStatus(ServerStatus.NORMAL);
				applicationContext.publishEvent(new TipEvent(new TipMess(spiderService.getBrandName(), "服务上线","服务上线")));
			}
		} catch (Exception e) {
			log.error("服务监控异常信息",e);
			//如果属于请求超时异常或请求被拒绝的异常则判定为服务下线
//			if (isServerStop(e)) {
				if (flag) {
					flag=false;
					updateBrandStatus(ServerStatus.ABNOMAL);
					applicationContext.publishEvent(new TipEvent(new TipMess(spiderService.getBrandName(), "服务下线","服务下线")));
				}
//			}
		}
	}
	private  void updateBrandStatus(String status){
		JSONObject param = new JSONObject();
		param.put("brandname", spiderService.getBrandCode());
		param.put("status", status);
		String body;
		try {
			body = Jsoup.connect(STATUS_URL).ignoreContentType(true)
					.header("Content-Type", "application/json").timeout(30000)
					.requestBody(param.toJSONString())
					.method(Method.POST).execute()
					.body();
			log.info("通知品牌维护反馈:{}",body);
		} catch (IOException e) {
			log.error("修改{}品牌状态失败",spiderService.getBrandName());
		}
	}
	private boolean isServerStop(Exception e){
		return (e.getCause() instanceof SocketTimeoutException 
				|| e.getCause() instanceof ConnectException
				|| e instanceof SocketTimeoutException 
				|| e instanceof ConnectException);
	}
	public static void main(String[] args){
	    String str1="[{\"enginnum\":\"\",\"createtime\":\"2018-09-29 13:30:24\",\"pulltime\":\"2018-09-29 13:30:40\",\"count\":1,\"vin\":\"LFV3A23C6C3084364\",\"id\":\"15381990242174686331414065998041\",\"brandname\":\"yqdz\",\"version\":2}]";
//	    String str2="[{\"enginnum\":\"\",\"createtime\":\"2018-09-29 09:39:36\",\"pulltime\":\"2018-09-29 09:41:50\",\"count\":1,\"vin\":\"LFV2A1BS8G4750591\",\"id\":\"15381851762234686331473766964895\",\"brandname\":\"yqdz\",\"version\":2}]";
//	    String str3="[{\"enginnum\":\"\",\"createtime\":\"2018-09-29 09:44:46\",\"pulltime\":\"2018-09-29 09:46:19\",\"count\":1,\"vin\":\"LFV2A11G793153924\",\"id\":\"15381854863564686331417887840684\",\"brandname\":\"yqdz\",\"version\":2}]";
//	    String str4="[{\"enginnum\":\"\",\"createtime\":\"2018-09-29 09:39:16\",\"pulltime\":\"2018-09-29 09:41:46\",\"count\":1,\"vin\":\"LFV3A23C8D3033983\",\"id\":\"15381851560224686331419683537680\",\"brandname\":\"yqdz\",\"version\":2}]";

        JSONArray array1 = JSON.parseArray(str1);
//        JSONArray array2 = JSON.parseArray(str2);
//        JSONArray array3 = JSON.parseArray(str3);
//        JSONArray array4 = JSON.parseArray(str4);

        LinkedHashMap<String, JSONObject> orderContainer = new LinkedHashMap<>();
        test(array1, orderContainer);
//        test(array2, orderContainer);
//        test(array3, orderContainer);
//        test(array4, orderContainer);

        File orderFile = new File("order/yqdz.txt");
        try {
            String orderStr = JSON.toJSONString(orderContainer);
            FileUtils.write(orderFile, orderStr, Charset.defaultCharset());
        } catch (Exception e) {
        }
        try {
            String orderStr = FileUtils.readFileToString(orderFile, Charset.defaultCharset());
            orderContainer = JSON.parseObject(orderStr, orderContainer.getClass());
            System.out.println(orderContainer);
        } catch (Exception e) {
        }

    }

    private static void test(JSONArray array1, LinkedHashMap<String, JSONObject> orderContainer) {
        for (Object obj : array1) {
            JSONObject order = (JSONObject) obj;
            orderContainer.put(order.getString("id"), order);
        }
    }
}
